К признакам глубины относится в психологии. Восприятие глубины пространства

Данная статья:

  • написана командой . Надеемся, что она Вам будет полезна. Приятного прочтения!
  • это одна из статей из нашего

Преобразование типов - это тема, которая может показаться сложной начинающим программировать на Java. Однако, заверим Вас, на самом деле всё просто. Главное понять по каким законам происходит взаимодействие между переменными и помнить об этом при написании программ . Итак, давайте разбираться.

В Java существует 2 типа преобразований - картинка Вам в помощь:

Напомним, что вся "Вселенная Java" состоит из:

  • примитивных типов (byte, short, int, long, char, float, double, boolean)
  • объектов

В данной статье мы:

  • рассмотрим преобразование типов для примитивных типов переменных
  • преобразование объектов (String, Scanner и др.) в этой статье не рассматривается, поскольку с объектами происходит отдельная «магия» - это тема для отдельной статьи.
Автоматическое преобразование

Ну, что ж, давайте попробуем разобраться что такое "автоматическое преобразование".

Помните, когда мы рассматривали типы переменных (в статье ), мы говорили, что переменная - это некоторый «контейнер» , в котором может храниться значение для дальнейшего использования в программе. Также мы говорили о том, что каждый тип переменной имеет свой диапазон допустимых значений и объем занимаемой памяти. Вот она табличка, где это все было расписано:

Так вот, к чему мы, собственно говоря, клоним. К тому, что совсем не просто так Вам давались диапазоны допустимых значений и объем занимаемой памяти 🙂

Давайте, сравним, например:

1. byte и short. byte имеет меньший диапазон допустимых значений, чем short. То есть byte это как бы коробочка поменьше, а short - это коробочка побольше. И значит, мы можем byte вложить в short.

2. byte и int . byte имеет меньший диапазон допустимых значений, чем int. То есть byte это как бы коробочка поменьше, а int - это коробочка побольше. И значит, мы можем byte вложить в int.

3. int и long. int имеет меньший диапазон допустимых значений, чем long. То есть int это как бы коробочка поменьше, а long - это коробочка побольше. И значит, мы можем int вложить в long.

Это и есть пример автоматического преобразования. Это можно схематически изобразить в виде вот такой картинки:

Давайте рассмотрим как это работает на практике.

Пример №1

Код №1 - если Вы запустите это код на своем компьютере,

class Test { public static void main(String args) { byte a = 15; byte b = a; System.out.println(b); } }

class Test {

byte a = 15 ;

byte b = a ;

Код №2 - если Вы запустите это код на своем компьютере, в консоли будет выведено число 15

class Test { public static void main(String args) { byte a = 15; int b = a; System.out.println(b); } }

class Test {

public static void main (String args ) {

byte a = 15 ;

int b = a ;

System . out . println (b ) ;

И-и-и? Вы думаете, что раз в консоль было выведено одно и то же число, и код №1 отличается от кода №2 всего лишь типом переменной b, то между ними нет никакой разницы? Э то не так.

В коде №2 присутствует автоматическое преобразование типов , а в коде №1 - нет:

Хотя число, в принципе, одно и то же, но теперь оно находится в бо льшем контейнере, который занимает больше места на диске. При этом, JVM выполняет автоматические преобразования за Вас. Она знает, что int больше чем byte .

Приведение типов

Другое дело если вы пытаетесь переложить что-то из большего контейнера в более маленький.

Вы можете знать, что в большем контейнере лежит то, что поместиться и в маленьком – но об этом не знает JVM, и пытается предохранить вас от ошибок.

Поэтому, вы должны «прямо сказать», что ситуация под контролем:

class Test { public static void main(String args) { int a=0; long b=15; a = (int) b; } }

class Test {

public static void main (String args ) {

int a = 0 ;

long b = 15 ;

a = (int ) b ;

Тут мы дописали (int) перед b . Если бы переменная a была, к примеру, типа byte , в скобках бы стояло (byte) . Общая формула выглядит так:

Она говорит "сделай из (большего) значения b переменную нужного мне (целевого) типа int ".

Если что-то пошло не так.

До этого мы рассматривали ситуации, предполагая, что мы точно знаем, что делаем. Но что если попытаться поместить в контейнер то, что туда не помещается?

Оказывается, в контейнере останется лишь то, что туда «влезло». К примеру, у чисел с плавающей точкой будет «отсекаться» дробная часть:

//пример 1 class Test { public static void main(String args) { double a=11.2345; int b=(int)a; System.out.println(b); // в консоли получится число 11 } }

//пример 1

class Test {

public static void main (String args ) {

double a = 11.2345 ;

int b = (int ) a ;

System . out . println (b ) ; // в консоли получится число 11

Надо помнить, что дробная часть не округляется , а отбрасывается .

А что будет, если мы попытаемся поместить число, которое выходит за допустимые границы? Например, если в byte (диапазон byte от -128 до 127) положить число 128? Думаете, мы получим 1? Нет. Мы получим -128:

class Test { public static void main(String args) { double a=128; byte b=(byte)a; System.out.println(b); //в консоли увидим -128 } }

Значение переменной при таком преобразовании можно рассчитать, но цель программиста – не допускать ситуации, когда значение выходит за допустимые границы, поскольку это может привести к неправильной работе программы.

Задания:
  1. Последовательно пропишите в компиляторе преобразования всех примитивных типов друг к другу, включая типы char и Составьте таблицу такого вида:
byte short char int long float double boolean
byte
short
char
int
Long
Float
double
boolean

На пересечении напишите: а – если преобразование происходит автоматически, на – если нужно использовать явное преобразование, х – если преобразование невозможно.

* приведение типа к самому себе называется тождественным – его прописывать не обязательно

  1. Посмотрите еще раз, какой размер имеет каждый примитивный тип. Попытайтесь составить блок-схему, показывающую, куда помещаются какие типы. Проведите стрелочки с надписью «расширяющее преобразование» и «сужающее преобразование».
Вопросы

На собеседовании на должность Junior Java Developer Вас могут спросить:

Что Вы знаете о преобразовании примитивных типов данных, есть ли потеря данных, можно ли преобразовать логический тип?

Попробуйте ответить на вопрос.

Подытожим:
  • Если Вы "кладёте" в больший контейнер содержимое меньшего контейнера», преобразование происходит автоматически, и ошибок возникать не должно.
  • Если есть необходимость положить «значение из большего контейнера в меньший», нужно быть осторожным, и пользоваться явным приведением типов.
  • При приведении float или double к целочисленным типам, дробная часть не округляется, а просто отбрасывается.
  • Тип boolean не приводится ни к одному из типов.
  • Тип char приводится к числовым типам, как код символа в системе UNICODE.
  • Если число больше своего контейнера, результат будет непредсказуемым.

В этой статье описана только часть материала на тему приведения типов. Существуют также приведения объектных типов, приведение к строке (ведь в строке может быть записано все что угодно, правда?) и автоматическое продвижение типов в выражениях.

Надеемся, что наша статья была Вам полезна. Также есть возможность записаться на наши курсы по Java в Киеве. Обучаем с нуля. Детальную информацию Вы можете найти у нас на .


В данном уроке мы расскажем вам о небольшой головной боли программистов — приведении типов. Что такое приведение типов? Это любое преобразование типа данных.
Например:

Int b = 3;
double a = 1.0 * b;//преобразование типов
a = (double)b;//преобразование типов

Таким образом можно увидеть два способа изменения типа:

  • Выполнение каких-то операций над объектом
  • Явное преобразование

К каким типам можно приводить? Можно приводить к таким типам данных, которые находятся в одной иерархии. Допустим можно привести целое число к вещественному и наоборот. Можно привести класс Student к классу User и так далее. Очевидно, что приводить строку к числу бесполезно, так как это разные объекты. В таком случае обычно пользуются специальными операциями.
У более менее опытных пользователей может возникнуть следующий вопрос:

Int b = 3;
double a = b;//преобразование типов 1
b = (int) a;//преобразование типов 2

Почему типу данных double можно присваивать тип данных int и компилятор не выдаст ошибку, а для того, чтобы double привести в int нужно явно указать тип? Оказывается безопасные преобразования, например от int к double или от сына к родителю называют расширяющими, т.е мы даем типу данных с более низкими возможностями расширится, например целому типу данных, даем возможность становится вещественным, расширяя его область применения. Преобразование называется расширяющим, если тип данных к которому мы приводим включает в себя тип данных который мы хотим привести для базовых типов.
Сужающие преобразования всегда связаны с некоторой потерей информации, например преобразовывая от double к int мы теряем все значения после запятой, что вызывает опасения у компьютера и только явное указание типа данных может уверить его, что мы делаем это преобразование в здравом уме и твердой памяти.
Рассмотрим еще раз пример с фигурами:

Public class Shape {
}
public class Square extends Shape {
}
Square square;
Shape shape = square;//расширяющие преобразование
square = shape;//сужающие преобразование

Казалось бы преобразовывая от сына к родителю мы наоборот сужаемся, а не расширяемся, в чем причина? А причина состоит в том, что на самом деле класс Square содержит всю информацию класса Shape и преобразовываясь от сына к отцу, мы только теряем информацию специфичную для сына, которая в данный момент может быть не важна, но преобразовываясь от Shape к Square мы можем получить такую ситуацию, что у нас просто нет данных, необходимой для работы класса, например у нас нет размера квадрата, если говорить о примере выше.
И в завершении урока рассмотрим оператор instanceof, он возвращает true если объект имеет заданный тип:

If(new Square() instanceof Shape){//false

Иногда возникают ситуации, когда у вас есть величина какого-то определенного типа, а вам нужно ее присвоить переменной другого типа. Для некоторых типов это можно проделать и без приведения типа, в таких случаях говорят об автоматическом преобразовании типов. В Java автоматическое преобразование возможно только в том случае, когда точности представления чисел переменной-приемника достаточно для хранения исходного значения. Такое преобразование происходит, например, при занесении литеральной константы или значения переменной типа byte или short в переменную типа int. Это называется расширением (widening ) или повышением (promotion ), поскольку тип меньшей разрядности расширяется (повышается) до большего совместимого типа. Размера типа int всегда достаточно для хранения чисел из диапазона, допустимого для типа byte, поэтому в подобных ситуациях оператора явного приведения типа не требуется. Обратное в большинстве случаев неверно, поэтому для занесения значения типа int в переменную типа byte необходимо использовать оператор приведения типа. Эту процедуру иногда называют сужением (narrowing ), поскольку вы явно сообщаете транслятору, что величину необходимо преобразовать, чтобы она уместилась в переменную нужного вам типа. Для приведения величины к определенному типу перед ней нужно указать этот тип, заключенный в круглые скобки. В приведенном ниже фрагменте кода демонстрируется приведение типа источника (переменной типа int) к типу приемника (переменной типа byte). Если бы при такой операции целое значение выходило за границы допустимого для типа byte диапазона, оно было бы уменьшено путем деления по модулю на допустимый для byte диапазон (результат деления по модулю на число - это остаток от деления на это число),

int а = 100;
byte b = (byte) а;

2.2.1. Автоматическое преобразование типов в выражениях

При вычислениях значения выражения точность, требуемая для хранения промежуточных результатов, зачастую должна быть выше, чем требуется для представления окончательного результата,

byte а = 40;
byte b = 50;
byte с = 100;
int d = a* b / с ;

Результат промежуточного выражения (а*b) вполне может выйти за диапазон допустимых для типа byte значений. Именно поэтому Java автоматически повышает тип каждой части выражения до типа int, так что для промежуточного результата (а* b) хватает места.

Автоматическое преобразование типа иногда может оказаться причиной неожиданных сообщений транслятора об ошибках. Например, показанный ниже код, хотя и выглядит вполне корректным, приводит к сообщению об ошибке на фазе трансляции. В нем мы пытаемся записать значение 50*2, которое должно прекрасно уместиться в тип byte, в байтовую переменную. Но из-за автоматического преобразования типа результата в int мы получаем сообщение об ошибке от транслятора - ведь при занесении int в byte может произойти потеря точности.

byte b = 50;
b = b* 2:
^ Incompatible type for =. Explicit cast needed to convert int to byte.
(Несовместимый тип для =. Необходимо явное преобразование int в byte)

Исправленный текст:
byte b = 50;
b = (byte) (b* 2);

что приводит к занесению в b правильного значения 100.

Если в выражении используются переменные типов byte, short и int, то во избежание переполнения тип всего выражения автоматически повышается до int. Если же в выражении тип хотя бы одной переменной - long, то и тип всего выражения тоже повышается до long. Не забывайте, что все целые литералы, в конце которых не стоит символ L (или 1), имеют тип int.

Если выражение содержит операнды типа float, то и тип всего выражения автоматически повышается до float. Если же хотя бы один из операндов имеет тип double, то тип всего выражения повышается до double. По умолчанию Java рассматривает все литералы с плавающей точкой как имеющие тип double. Приведенная ниже про1рамма показывает, как повышается тип каждой величины в выражении для достижения соответствия со вторым операндом каждого бинарного оператора.

class Promote {
public static void main (String args ) {
byte b= 42;
char с = "a’;
shorts = 1024;
int i = 50000;
float f = 5.67f;
doubled =.1234;
double result = (f*b) + (i/ c) - (d* s);
System, out. println ((f* b)+ "+ "+ (i / c)+ " -" + (d* s));
System, out. println ("result = "+ result); }
}

Подвыражение f*b - это число типа float, умноженное на число типа byte, поэтому его тип автоматически повышается до float. Тип следующего подвыражения i / с (int, деленный на char) повышается до int. Аналогично этому тип подвыражения d*s (double, умноженный на short) повышается до double. На следующем шаге вычислений мы имеем дело с тремя промежуточными результатами типов float, int и double. Сначала при сложении первых двух тип int повышается до float и получается результат типа float. При вычитании из него значения типа double тип результата повышается до double. Окончательный результат всего выражения - значение типа double.

Теперь, когда мы познакомились со всеми простыми типами, включая целые и вещественные числа, символы и логические переменные, давайте попробуем собрать всю информацию вместе. В приведенном ниже примере создаются переменные каждого из простых типов и выводятся значения этих переменных.

class SimpleTypes {
public static void main(String args ) {
byte b = 0x55;
short s = 0x55ff;
int i = 1000000;
long l = 0xffffffffL;
char с = ’a’;
float f= .25f;
double d = .00001234;
boolean bool = true;
System.out.println("byte b = " + b);
System.out.println("short s = " +s);
System.out.println("int i =” + i);
System.out.println("long 1 = " + l);
System.out.println("char с =” + с );
System.out.println("float f = " + f);
System.out.println("double d = " + d);
System.out.println("boolean bool =” + bool); }
}

Запустив эту программу, вы должны получить результат, показанный ниже:

byte b = 85
shorts = 22015
int i = 1000000
long 1 = 4294967295
char с = a
float f = 0.25
double d=1.234e-005
boolean bool = true

Обратите внимание на то, что целые числа печатаются в десятичном представлении, хотя мы задавали значения некоторых из них в шестнадцатиричном формате.

Восприятие глубины, или дифференциальное восприятие расстояния, является результатом работы зрительных и слуховых анализаторов. Что касается зрения, то восприятие глубины основано на монокулярных и бинокулярных признаках . Монокулярными являются признаки, которые могут восприниматься не только двумя, но и одним глазом. признаки отражают совместную деятельность обоих глаз.

К монокулярным признакам относят: окклюзию, знакомость размера, параллакс движения, линейную перспективу, градиент текстуры и затенение . Большинство монокулярных пространственных признаков статичны, т.е. они воспринимаются в том случае, если и наблюдатель, и наблюдаемый объекты неподвижны.

Окклюзия , или интерпозиция , – это признак, который обеспечивает возникновение эффекта глубины, когда один наблюдаемый предмет частично закрывает другой. Несмотря на то, что большая часть белого треугольника отсутствует, зрительная система «достраивает » изображение, чтобы воссоздать общую смысловую структуру, причем одновременно возникает иллюзия удаленности треугольника от трех черных кругов.

Знакомость размера , т.е. присутствие в нашем перцептивном опыте представлений о размере объекта, позволяет нам использовать информацию о его ретинальном размере для того, чтобы понять, насколько он удален от наблюдателя. Например, в исследовании Н. Иттельсона испытуемым предъявляли три игральные карты. Одна из карт была стандартного размера, вторая – в два раза больше, а третья – в два раза меньше обычной карты. Все карты предъявляли поочередно с расстояния 7,5 фута. Оказалось, что испытуемые оценивали расстояние до карт каждый раз по-разному. Расстояние до карты стандартного размера, по их мнению, составляло 7,5 фута, до карты в два раза меньше обычной – 15 футов и до карты вдвое большей – 4,6 фута. Очевидно, что на оценку дистанции повлияла убежденность испытуемых в том, что все предъявляемые карты должны быть одного размера.

Параллакс движения (греч. parataxis – перемена, изменения ) – это монокулярный источник информации о глубине и взаимном расположении объектов, он возникает в результате перемещения наблюдателя или наблюдаемых объектов. Более точное определение монокулярного параллакса движения приводит :

Параллакс движения это изменения во взаимном расположении ретинальных изображений объектов, лежащих на разном удалении от наблюдателя, вызванные поворотом его головы.

С параллаксом движения связаны явления, наблюдаемые через боковое стекло быстро движущегося автомобиля. Наблюдателю кажется, что объекты, расположенные выше точки фиксации взгляда, движутся в направлении движения автомобиля. Напротив, объекты, расположенные ниже точки фиксации, движутся в противоположном движению автомобиля направлении.

Линейная перспектива – это планомерное уменьшение величины удаленных предметов и расстояний между ними, создающее впечатление глубины при восприятии плоскостных изображений. Типичным примером линейной перспективы является восприятие изображения железнодорожных рельсов или параллельных линий: хотя и те, и другие параллельны, создается впечатление, что в определенной точке (точке схода) они пересекаются. Линейная перспектива широко используется в живописи. В настоящее время общепризнано, что создателем теории линейной перспективы был итальянский скульптор и архитектор XV в. Ф. Брунеллески .

Градиент текстуры – монокулярный признак восприятия глубины, при наличии которого по мере удаления от нас фрагментов текстурированной поверхности образующие ее элементы начинают казаться более мелкими и уплотненными.

В качестве градиента текстуры плоских поверхностей могут выступать постепенные изменения величины, формы или пространственного расположения элементов, образующие паттерн текстуры и создающие впечатление глубины или удаленности объектов. Например, представьте себе уходящий вдаль берег, покрытый галькой: чем дальше галька, тем более плотной она кажется.

Поскольку плотность заполнения берега галькой примерно одинакова, градиент изменения текстуры по мере увеличения расстояния от наблюдателя дает глазу непосредственную информацию о структуре и глубине зрительного пространства. Так, градиент текстуры, спроецированный на сетчатку, передает структуру трехмерного пространства.

Затенение - монокулярный признак глубины, возникающий в результате уменьшения освещенности предметов по мере их удаления от наблюдателя или источника света и чередования света и тени. БэйбиФорум отмечает, что уже к трем годам дети привыкают, что свет падает сверху, и исходя из интенсивности освещенности умеют отличать выпуклости от выгнутостей. является важным признаком восприятия глубины еще и потому, что, как мы знаем из перцептивного опыта, только трехмерные предметы имеют тень.

В живописи за счет игры света и тени не только достигается эффект глубины, но и создаются изображения форм. Клеффнер и Рамачандран даже полагают, что существуют специальные нейроны, «вычленяющие » из затененности информацию о форме объектов.